﻿
#region Using Directives.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using ActiproSoftware.Products.SyntaxEditor;
using ActiproSoftware.SyntaxEditor;
using ActiproSoftware.WinUICore;
using GDFlacTool.Properties;

#endregion

namespace GDFlacTool.Forms
{
    public partial class FormFindReplace : Form
    {
        #region Fields.

        private FindReplaceOptions _options;
        private SyntaxEditor _syntaxEditor;
        private bool _runOnce = false;
        private List<string> _searchWords = new List<string>();
        private List<string> _replaceWords = new List<string>(); 

        #endregion

        #region Delegates.

        [Category("Action"), Description("Occurs when there is a status change.")]
        public event FindReplaceStatusChangeEventHandler StatusChanged;

        #endregion 

        #region Constructors.

        public FormFindReplace(SyntaxEditor syntaxEditor, FindReplaceOptions options)
        {
            InitializeComponent();

            if (options == null)
                throw new ArgumentNullException("options");
                //options = new FindReplaceOptions();


            _syntaxEditor = syntaxEditor;

            _options = options;

            string[] search = {"Regular Expressions", "Wildcards"};

            dplSearchType.Items.AddRange(search);

            dplSearchType.SelectedIndex = 0;

            UpdateUIFromFindReplaceOptions();
        }

        #endregion

        #region Properties.

        public FindReplaceOptions Options
        {
            get
            {
                return _options;
            }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("Options");

                _options = value;

                UpdateUIFromFindReplaceOptions();
            }
        }

        public SyntaxEditor SyntaxEditor
        {
            get
            {
                return _syntaxEditor;
            }
            set
            {
                _syntaxEditor = value;
            }
        }

        #endregion

        #region Private Methods.

        private void UpdateUIFromFindReplaceOptions()
        {
            cboFind.Text = _options.FindText;
            cboReplace.Text = _options.ReplaceText;
            chkMatchCase.Checked = _options.MatchCase;
            chkMatchWholeWord.Checked = _options.MatchWholeWord;
            //chkSearchUp.Checked = _options.SearchUp;
            rbnUp.Checked = _options.SearchUp;
            chkSearchHiddenText.Checked = _options.SearchHiddenText;
            chkSearchInSelection.Checked = _options.SearchInSelection;
            chkSearchType.Checked = (_options.SearchType != FindReplaceSearchType.Normal);
            dplSearchType.SelectedIndex = (_options.SearchType != FindReplaceSearchType.Wildcard ? 0 : 1);
        }

        private void UpdateFindReplaceOptionsFromUI()
        {
            _options.FindText = cboFind.Text;
            _options.ReplaceText = cboReplace.Text;
            _options.MatchCase = chkMatchCase.Checked;
            _options.MatchWholeWord = chkMatchWholeWord.Checked;
            _options.SearchHiddenText = chkSearchHiddenText.Checked;
            _options.SearchInSelection = chkSearchInSelection.Checked;
            //_options.SearchUp = chkSearchUp.Checked;
            _options.SearchUp = rbnUp.Checked;
            _options.SearchType = (!chkSearchType.Checked ? FindReplaceSearchType.Normal :
                                            (dplSearchType.SelectedIndex == 0 ? FindReplaceSearchType.RegularExpression : FindReplaceSearchType.Wildcard));
        }

        #endregion

        #region Button Events.

        private void btnClose_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void btnFind_Click(object sender, EventArgs e)
        {
            UpdateFindReplaceOptionsFromUI();

            if(_syntaxEditor == null)
                return;

            OnStatusChanged(new FindReplaceStatusChangeEventArgs(FindReplaceStatusChangeType.Find, _options));

            FindReplaceResultSet resultSet;

            try
            {
                resultSet = _syntaxEditor.SelectedView.FindReplace.Find(_options);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, SR.GetString("FindReplaceForm_Error_Message") + "\r\n" + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (resultSet.PastDocumentEnd)
            {
                OnStatusChanged(new FindReplaceStatusChangeEventArgs(FindReplaceStatusChangeType.PastDocumentEnd, _options));
            }

            if (resultSet.PastSearchStartOffset)
            {
                MessageBox.Show(this, SR.GetString("FindReplaceForm_PastSearchStartOffset_Message"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            if (resultSet.Count == 0)
                MessageBox.Show(this, SR.GetString("FindReplaceForm_NotFound_Message"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void txtFind_TextChanged(object sender, EventArgs e)
        {
            //
        }

        private void btnFindInsert_Click(object sender, EventArgs e)
        {
            OwnerDrawContextMenu menu = new OwnerDrawContextMenu();

            if (dplSearchType.SelectedIndex == 0)
            {
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_SingleCharacter"), -1,(mnuItem_Click), Shortcut.None, "."));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_ZeroOrMore"), -1, (mnuItem_Click), Shortcut.None, "*"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_OneOrMore"), -1, (mnuItem_Click), Shortcut.None, "+"));
                menu.MenuItems.Add(new OwnerDrawMenuItem("-"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_BeginningOfLine"), -1, (mnuItem_Click), Shortcut.None, "^"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_EndOfLine"), -1, (mnuItem_Click), Shortcut.None, "$"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_WordBoundary"), -1, (mnuItem_Click), Shortcut.None, "\\b"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_Whitespace"), -1, (mnuItem_Click), Shortcut.None, "\\s"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_LineBreak"), -1, (mnuItem_Click), Shortcut.None, "\\n"));
                menu.MenuItems.Add(new OwnerDrawMenuItem("-"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_OneCharacterInSet"), -1, (mnuItem_Click), Shortcut.None, "[ ]"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_OneCharacterNotInSet"), -1, (mnuItem_Click), Shortcut.None, "[^ ]"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_Or"), -1, (mnuItem_Click), Shortcut.None, "|"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_CharacterEscape"), -1, (mnuItem_Click), Shortcut.None, "\\"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_RegularExpression_Group"), -1, (mnuItem_Click), Shortcut.None, "( )"));
            }
            else
            {
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_Wildcard_ZeroOrMore"), -1, (mnuItem_Click), Shortcut.None, "*"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_Wildcard_AnySingleCharacter"), -1, (mnuItem_Click), Shortcut.None, "?"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_Wildcard_AnySingleDigit"), -1, (mnuItem_Click), Shortcut.None, "#"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_Wildcard_OneCharacterInSet"), -1, (mnuItem_Click), Shortcut.None, "[ ]"));
                menu.MenuItems.Add(new OwnerDrawMenuItem(SR.GetString("FindReplaceForm_Wildcard_OneCharacterNotInSet"), -1, (mnuItem_Click), Shortcut.None, "[! ]"));
            }

            menu.Show(btnFindInsert, new Point(btnFindInsert.ClientRectangle.Right, btnFindInsert.ClientRectangle.Top));
        }

        private void btnClearAllMarks_Click(object sender, EventArgs e)
        {
            UpdateFindReplaceOptionsFromUI();

            if (_syntaxEditor == null)
                return;

            if(chkMarkWith.Checked)
                _syntaxEditor.Document.LineIndicators.Clear(BookmarkLineIndicator.DefaultName);
            else
            {
                _syntaxEditor.Document.SpanIndicatorLayers.Clear();
            }
            
        }

        private void btnMarkAll_Click(object sender, EventArgs e)
        {
            UpdateFindReplaceOptionsFromUI();

            if (_syntaxEditor == null)
                return;

            FindReplaceResultSet resultSet;

            try
            {
                if (chkMarkWith.Checked)
                    resultSet = _syntaxEditor.SelectedView.FindReplace.MarkAll(_options);
                else
                    resultSet = _syntaxEditor.SelectedView.FindReplace.MarkAll(_options, typeof(CurrentStatementSpanIndicator));
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, SR.GetString("FindReplaceForm_Error_Message") + "\r\n" + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (resultSet.Count == 0)
                MessageBox.Show(this, SR.GetString("FindReplaceForm_NotFound_Message"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void btnReplace_Click(object sender, EventArgs e)
        {
            UpdateFindReplaceOptionsFromUI();

            if (_syntaxEditor == null)
                return;

            OnStatusChanged(new FindReplaceStatusChangeEventArgs(FindReplaceStatusChangeType.Replace, _options));

            FindReplaceResultSet resultSet;

            try
            {
                resultSet = _syntaxEditor.SelectedView.FindReplace.Replace(_options);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, SR.GetString("FindReplaceForm_Error_Message") + "\r\n" + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (resultSet.PastDocumentEnd)
            {
                OnStatusChanged(new FindReplaceStatusChangeEventArgs(FindReplaceStatusChangeType.PastDocumentEnd, _options));
            }

            if (resultSet.Count == 0)
            {
                if ((resultSet.PastDocumentEnd) && (resultSet.ReplaceOccurred))
                    MessageBox.Show(this, SR.GetString("FindReplaceForm_PastSearchStartOffset_Message"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
                else
                    MessageBox.Show(this, SR.GetString("FindReplaceForm_NotFound_Message"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        
        private void btnReplaceAll_Click(object sender, EventArgs e)
        {
            UpdateFindReplaceOptionsFromUI();

            if (_syntaxEditor == null)
                return;

            FindReplaceResultSet resultSet;
            
            try
            {
                resultSet = _syntaxEditor.SelectedView.FindReplace.ReplaceAll(_options);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, SR.GetString("FindReplaceForm_Error_Message") + "\r\n" + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (resultSet.Count == 0)
            {
                MessageBox.Show(this, SR.GetString("FindReplaceForm_NotFound_Message"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            MessageBox.Show(this, resultSet.Count + " " + SR.GetString("FindReplaceForm_OccurrencesReplaced_Message"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        #endregion

        #region Form Event Implementation.

        protected virtual void OnStatusChanged(FindReplaceStatusChangeEventArgs e)
        {
            if (StatusChanged != null)
                StatusChanged(this, e);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            double tr = Convert.ToDouble(FindReplaceSettings.Default.Transparancy, CultureInfo.CurrentCulture);

            int tr1 = Convert.ToInt32((tr * 100), CultureInfo.CurrentCulture);

            rbtAlways.Checked = FindReplaceSettings.Default.AlwaysTransparancy;
            
            chkTransparancy.Checked = FindReplaceSettings.Default.UseTransparancy;

            if(rbtAlways.Checked && chkTransparancy.Checked)
                trbTransparancy.Value = tr1;

            Point p = new Point(FindReplaceSettings.Default.LocationX, FindReplaceSettings.Default.LocationY);

            Location = p;

            if (FindReplaceSettings.Default.SearchWords == null)
                FindReplaceSettings.Default.SearchWords = new StringCollection();
            
            _searchWords = FindReplaceSettings.Default.SearchWords.Cast<string>().ToList();

            if (FindReplaceSettings.Default.ReplaceWords == null)
                FindReplaceSettings.Default.ReplaceWords = new StringCollection();

            _replaceWords = FindReplaceSettings.Default.ReplaceWords.Cast<string>().ToList();

            cboFind.Items.AddRange(_searchWords.ToArray());

            cboReplace.Items.AddRange(_replaceWords.ToArray());
        }

        protected override void OnActivated(EventArgs e)
        {
            base.OnActivated(e);

            cboFind.SelectAll();
            cboFind.Focus();

            if (rbtOnLosingFocus.Checked && chkTransparancy.Checked)
            {
                Opacity = 100;
            }

            if (rbtAlways.Checked && chkTransparancy.Checked)
            {
                Opacity = (double)trbTransparancy.Value / 100;
            }
        }

        protected override void OnDeactivate(EventArgs e)
        {
            base.OnDeactivate(e);

            if (rbtOnLosingFocus.Checked && chkTransparancy.Checked)
            {
                Opacity = (double)trbTransparancy.Value / 100;
            }
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            OnStatusChanged(new FindReplaceStatusChangeEventArgs(FindReplaceStatusChangeType.Ready, _options));

            base.OnClosing(e);

            FindReplaceSettings.Default.Transparancy = (double)trbTransparancy.Value / 100;
            FindReplaceSettings.Default.UseTransparancy = chkTransparancy.Checked;
            FindReplaceSettings.Default.LocationX = Location.X;
            FindReplaceSettings.Default.LocationY = Location.Y;
            FindReplaceSettings.Default.AlwaysTransparancy = rbtAlways.Checked;

            if (FindReplaceSettings.Default.SearchWords == null)
            {
                FindReplaceSettings.Default.SearchWords = new StringCollection();
            }
            else
            {
                FindReplaceSettings.Default.SearchWords.Clear();
            }

            FindReplaceSettings.Default.SearchWords.AddRange(_searchWords.ToArray());

            if (FindReplaceSettings.Default.ReplaceWords == null)
            {
                FindReplaceSettings.Default.ReplaceWords = new StringCollection();
            }
            else
            {
                FindReplaceSettings.Default.ReplaceWords.Clear();
            }

            FindReplaceSettings.Default.ReplaceWords.AddRange(_replaceWords.ToArray());


            FindReplaceSettings.Default.Save();

            // Cancel the close and hide the form instead (for reuse)
            e.Cancel = true;
            if (Owner != null)
                Owner.Activate();
            Hide();
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            if (Visible)
            {
                UpdateUIFromFindReplaceOptions();
            }
        }

        #endregion

        #region Control Events.

        private void mnuItem_Click(object sender, EventArgs e)
        {
            cboFind.SelectedText = ((OwnerDrawMenuItem)sender).Tag.ToString();
        }

        private void chkSearchType_CheckedChanged(object sender, EventArgs e)
        {
            btnFindInsert.Enabled = chkSearchType.Checked;
            dplSearchType.Enabled = chkSearchType.Checked;
        }

        private void chkTransparancy_CheckedChanged(object sender, EventArgs e)
        {
            if(chkTransparancy.Checked)
            {
                if (rbtAlways.Checked)
                {
                    Opacity = (double)trbTransparancy.Value / 100;
                }
                rbtOnLosingFocus.Enabled = true;
                rbtAlways.Enabled = true;
                trbTransparancy.Enabled = true;
            }
            else
            {
                Opacity = 100;
                rbtOnLosingFocus.Enabled = false;
                rbtAlways.Enabled = false;
                trbTransparancy.Enabled = false;
            }
        }

        private void trbTransparancy_ValueChanged(object sender, EventArgs e)
        {
            if(rbtAlways.Checked)
                Opacity = (double) trbTransparancy.Value / 100;
        }

        private void FormFindReplace_Paint(object sender, PaintEventArgs e)
        {
            if (chkTransparancy.Checked && _runOnce)
            {
                Opacity = (double) trbTransparancy.Value / 100;
                _runOnce = false;
            }
        }

        private void rbtAlways_CheckedChanged(object sender, EventArgs e)
        {
            if(rbtAlways.Checked)
            {
                Opacity = (double) trbTransparancy.Value / 100;
            }
            else
            {
                Opacity = 100;
            }
        }

        private void cboFind_Leave(object sender, EventArgs e)
        {
            string word = cboFind.Text;

            if(string.IsNullOrEmpty(word))
                return;

            if(!_searchWords.Contains(word))
            {
                if(_searchWords.Count == 10)
                {
                    _searchWords.RemoveAt(9);
                }
                
                _searchWords.Insert(0, word);
                
            }
            else
            {
                _searchWords.Remove(word);
                _searchWords.Insert(0, word);
            }

            cboFind.Items.Clear();
            cboFind.Items.AddRange(_searchWords.ToArray());
        }

        private void cboFind_TextChanged(object sender, EventArgs e)
        {
            btnFind.Enabled = (cboFind.Text.Length > 0);
            btnReplace.Enabled = btnFind.Enabled;
            btnReplaceAll.Enabled = (cboFind.Text.Length > 0);
            btnMarkAll.Enabled = btnReplaceAll.Enabled;
        }

        private void cboReplace_Leave(object sender, EventArgs e)
        {
            string word = cboReplace.Text;

            if (string.IsNullOrEmpty(word))
                return;

            if (!_replaceWords.Contains(word))
            {
                if (_replaceWords.Count == 10)
                {
                    _replaceWords.RemoveAt(9);
                }

                _replaceWords.Insert(0, word);

            }
            else
            {
                _replaceWords.Remove(word);
                _replaceWords.Insert(0, word);
            }

            cboReplace.Items.Clear();
            cboReplace.Items.AddRange(_replaceWords.ToArray());
        }

        #endregion
    }
}
